home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The CICA Windows Explosion!
/
The CICA Windows Explosion! - Disc 2.iso
/
programr
/
genmix1b.zip
/
GENMIX
/
SRC
/
PORTWAVE.C
< prev
Wrap
C/C++ Source or Header
|
1995-04-15
|
11KB
|
501 lines
/* -------- PORTWAVE.C -- Low level sound output
*/
#include "port.h"
#if iswin
#define inifile "portwave.ini"
/*
Private profile string format:
[ manu=[manuid] prod=[prodid] #[num] ]
name= [prodname]
version= [verhi].[verlo]
whatversion= [ all thishi thishilo ]
8bit11khzmono= [BlockSize] [PlayAhead] [ReMix] [UseGetPos]
8bit11khzstereo=[BlockSize] [PlayAhead] [ReMix] [UseGetPos]
8bit22khzmono= [BlockSize] [PlayAhead] [ReMix] [UseGetPos]
8bit22khzstereo=[BlockSize] [PlayAhead] [ReMix] [UseGetPos]
8bit44khzmono= [BlockSize] [PlayAhead] [ReMix] [UseGetPos]
8bit44khzstereo=[BlockSize] [PlayAhead] [ReMix] [UseGetPos]
16bit11khzmono= [BlockSize] [PlayAhead] [ReMix] [UseGetPos]
16bit11khzstereo=[BlockSize] [PlayAhead] [ReMix] [UseGetPos]
16bit22khzmono= [BlockSize] [PlayAhead] [ReMix] [UseGetPos]
16bit22khzstereo=[BlockSize] [PlayAhead] [ReMix] [UseGetPos]
16bit44khzmono= [BlockSize] [PlayAhead] [ReMix] [UseGetPos]
16bit44khzstereo=[BlockSize] [PlayAhead] [ReMix] [UseGetPos]
*/
static short waveinited = 0;
static long wavedatarate;
static short wavesamplesize;
static short numplaying;
static short curplaying;
static short nextplay;
static short usegetpos;
static long blocknumsamp;
static PWAVEHDR pbuf[16];
static HANDLE hbuf[16];
UINT outdev;
static HWAVEOUT hwo;
static int playahead;
static int numblocks;
static int blocksize;
static int immremix;
static void sounderror(MMRESULT err, short num)
{
int res;
char msg[256], errmsg[128];
waveOutGetErrorText(err, (LPTSTR)errmsg, 128);
sprintf(msg, "Sound Error %d:\n%s [%d]\n\n"
"Select OK to continue, Cancel to abort.",
err, errmsg, num);
res = MessageBox(NULL, msg, "Sound Error", MB_TASKMODAL|
MB_ICONEXCLAMATION|MB_OKCANCEL);
if (res==IDCANCEL) portFatalError(badmem, num);
return;
}
static void soundwaitall(void)
{
short i;
short done;
do {
done = 1;
for (i=0; i<numblocks; i++)
if (!(pbuf[i]->dwFlags & WHDR_DONE)) done = 0;
} while (!done);
return;
}
void CALLBACK soundcallback(HWAVEOUT hwaveout, UINT wmsg,
DWORD dwinst, PWAVEHDR pwhcur, DWORD param2)
{
int i;
if (wmsg != WOM_DONE) return;
// locate block
for (i=0; i<numblocks; i++)
if (pbuf[i] == pwhcur) break;
if (i >= numblocks) return;;
// advance ring buffer control pointers
numplaying--;
curplaying = i + 1;
if (curplaying >= numblocks) curplaying = 0;
// start timing next packet
if (numplaying)
pbuf[curplaying]->dwUser = timeGetTime();
return;
}
char drivername[32];
rescode waveOpen(waveRate rate, waveBits bits, waveSpeak speak,
int *pblocksiz, int *pahead, int *premix)
{
PCMWAVEFORMAT wf;
MMRESULT res;
UINT idev;
int i;
WAVEOUTCAPS woc;
if (waveinited) return 0;
wavesamplesize = (short) bits * (short) speak;
wavedatarate = waveRateBase * (long) rate;
// open output device
wf.wf.wFormatTag = WAVE_FORMAT_PCM;
wf.wf.nChannels = (short) speak;
wf.wf.nSamplesPerSec = wavedatarate;
wf.wf.nAvgBytesPerSec = wavedatarate * (long) wavesamplesize;
wf.wBitsPerSample = (short) bits * 8;
wf.wf.nBlockAlign = wavesamplesize;
// try all available output devices
idev=waveOutGetNumDevs();
outdev = 0;
while (outdev<idev) {
#if WINVER >= 0x0400
if (!waveOutOpen(&hwo, outdev, (WAVEFORMATEX*) &wf,
(DWORD)soundcallback, 0, CALLBACK_FUNCTION)) break;
#else
if (!waveOutOpen(&hwo, outdev, (WAVEFORMAT*) &wf,
(DWORD)soundcallback, 0, CALLBACK_FUNCTION)) break;
#endif
// shut off any playing sound and try again
if (outdev == 0)
{
sndPlaySound(NULL, 0);
#if WINVER >= 0x0400
if (!waveOutOpen(&hwo, outdev, (WAVEFORMATEX*) &wf,
(DWORD)soundcallback, 0, CALLBACK_FUNCTION)) break;
#else
if (!waveOutOpen(&hwo, outdev, (WAVEFORMAT*) &wf,
(DWORD)soundcallback, 0, CALLBACK_FUNCTION)) break;
#endif
}
outdev++;
}
if (idev==outdev) {
// try using wave mapper
outdev = WAVE_MAPPER;
#if WINVER >= 0x0400
res = waveOutOpen(&hwo, WAVE_MAPPER, (WAVEFORMATEX*) &wf,
(DWORD)soundcallback, 0, CALLBACK_FUNCTION);
#else
res = waveOutOpen(&hwo, WAVE_MAPPER, (WAVEFORMAT*) &wf,
(DWORD)soundcallback, 0, CALLBACK_FUNCTION);
#endif
if (!res) {
// get real output device number
res = waveOutGetID(hwo, &outdev);
if (res) {
sounderror(res, 0);
return 1;
}
}
else {
sounderror(res, 1);
return 1;
}
}
// reset sound device
res = waveOutReset(hwo);
if (res) {
sounderror(res, 2);
return 1;
}
{
char formatstr[32];
char verstr[16];
char vermatchstr[8];
char datastr[32];
int num, verhi, verlo;
char drvname[32];
res = waveOutGetDevCaps(outdev, &woc, sizeof(WAVEOUTCAPS));
if (res) {
sounderror(res, 3);
return 1;
}
num = 0;
do {
sprintf(drivername, "manu=%x prod=%x #%d", (int)woc.wMid,
(int)woc.wPid, num);
GetPrivateProfileString(drivername, "version", "", verstr,
sizeof(verstr),inifile);
if (verstr[0])
{
if (2 != sscanf(verstr, "%x.%x", &verhi, &verlo))
{
sounderror(0, 4);
return 1;
}
GetPrivateProfileString(drivername, "whatversion", "all",
vermatchstr, sizeof(vermatchstr), inifile);
if (strcmp("all", vermatchstr)) break;
if (strcmp("thishi", vermatchstr) == 0 &&
verhi == HIBYTE(woc.vDriverVersion) ) break;
if (strcmp("thishilo", vermatchstr) == 0 &&
verhi == HIBYTE(woc.vDriverVersion) &&
verlo == LOBYTE(woc.vDriverVersion) ) break;
num++;
}
else break;
} while (1);
if (!verstr[0]) strcpy(drvname, "default");
else strcpy(drvname, drivername);
sprintf(formatstr, "%dbit%dkhz%s", bits==waveBits8 ? 8 :16,
11 * (int)rate, speak==waveSpeakMono ? "mono" : "stereo");
GetPrivateProfileString(drvname, formatstr, "", datastr,
sizeof(datastr), inifile);
if (4 != sscanf(datastr, "%d %d %d %d", &blocksize, &playahead,
&immremix, &usegetpos))
{
MessageBox(NULL, "Please copy the file PORTWAVE.INI\nto your Windows directory.",
"Fatal Error", MB_TASKMODAL|MB_ICONEXCLAMATION|MB_OK);
sounderror(0, 7);
return 1;
}
}
// allocate output buffers
numblocks = playahead + 1;
blocknumsamp = blocksize / wavesamplesize;
// initialize output headers
for (i=0; i<numblocks; i++) {
hbuf[i] = GlobalAlloc(GMEM_MOVEABLE|GMEM_SHARE,
sizeof(WAVEHDR) + blocksize);
pbuf[i] = (PWAVEHDR) GlobalLock(hbuf[i]);
if (!pbuf[i]) return 1;
pbuf[i]->dwBufferLength = blocksize;
pbuf[i]->dwBytesRecorded = blocksize;
pbuf[i]->dwUser = 0;
pbuf[i]->dwFlags = WHDR_DONE;
pbuf[i]->dwLoops = 0;
pbuf[i]->lpData = (LPSTR)(pbuf[i]) + sizeof(WAVEHDR);
res = waveOutPrepareHeader(hwo, pbuf[i], sizeof(WAVEHDR));
if (res) {
sounderror(res, 3);
return 1;
}
}
// initialize ring buffer
waveinited = 1;
numplaying = 0;
curplaying = 0;
nextplay = -1;
*pblocksiz = blocksize / wavesamplesize;
*pahead = playahead;
*premix = immremix;
return 0;
}
rescode waveClose()
{
int i;
MMRESULT res;
if (!waveinited) return 0;
// reset wave device prior to closing
res = waveOutReset(hwo);
if (res) {
sounderror(res, 9);
return 1;
}
// sit and spin while buffer clears
soundwaitall();
// dispose of output headers
for (i=0; i<numblocks; i++) {
res = waveOutUnprepareHeader(hwo, pbuf[i], sizeof(WAVEHDR));
if (res) {
sounderror(res, 5);
return 1;
}
GlobalUnlock(hbuf[i]);
GlobalFree(hbuf[i]);
}
// close output device
res = waveOutClose(hwo);
if (res) {
sounderror(res, 4);
return 1;
}
waveinited = 0;
return 0;
}
rescode waveReset()
{
MMRESULT res;
if (!waveinited) return 1;
// reset the device
res = waveOutReset(hwo);
if (res) {
sounderror(res, 6);
return 1;
}
// sit and spin until the output buffer is empty
soundwaitall();
return 0;
}
rescode waveGetPlayPtr(pmem *pptr)
{
if (!waveinited) return 1;
if (nextplay != -1) portFatalError(badlog, 0);
if (numplaying >= numblocks) portFatalError(badlog,0);
// return a pointer to the buffer after the last one playing
nextplay = curplaying + numplaying;
if (nextplay >= numblocks) nextplay -= numblocks;
*pptr = pbuf[nextplay]->lpData;
return 0;
}
rescode wavePlay()
{
MMRESULT res;
if (!waveinited) return 1;
if (nextplay == -1) portFatalError(badlog, 0);
// start timing this block if it's going out immediatly
if (!numplaying) {
curplaying = nextplay;
pbuf[nextplay]->dwUser = timeGetTime();
waveOutPause(hwo);
}
// play sound packet
res = waveOutWrite(hwo, pbuf[nextplay], sizeof(WAVEHDR));
if (res) {
sounderror(res, 7);
return 1;
}
if (!numplaying) waveOutRestart(hwo);
numplaying++;
nextplay = -1;
return 0;
}
rescode waveGetSampleCount(long *psize)
{
DWORD elapsed;
long sampplaying;
long samppacket;
static long np,cp;
MMRESULT res;
MMTIME mmt;
if (!waveinited) return 1;
np = numplaying;
cp = curplaying;
// get the total of all full or partial packets playing
sampplaying = np * blocknumsamp;
// subtract a fractional packet, if any
if (np) {
if (usegetpos)
{
mmt.wType = TIME_SAMPLES;
res = waveOutGetPosition(hwo, &mmt, sizeof(mmt));
if (res) sounderror(res, 8);
if (mmt.wType != TIME_SAMPLES) sounderror(res, 9);
samppacket = mmt.u.sample;
}
else {
// measure number of samples that have played
elapsed = timeGetTime() - pbuf[cp]->dwUser;
samppacket = (long)elapsed * (long)wavedatarate / 1000L;
}
if (samppacket < 0) samppacket = 0;
else if (samppacket >= blocknumsamp) samppacket = blocknumsamp-1;
sampplaying -= samppacket;
}
*psize = sampplaying;
return 0;
}
rescode waveGetVolume(short *pvol)
{
DWORD v;
MMRESULT res;
if (!waveinited) return 1;
#if WINVER >= 0x0400
res = waveOutGetVolume(hwo, &v);
#else
res = waveOutGetVolume(outdev, &v);
#endif
// ignore error if function not supported
if (res==MMSYSERR_NOTSUPPORTED) {
*pvol = 7;
return 0;
}
if (res) {
sounderror(res, 10);
return 1;
}
// convert to 0..7 scale
v = LOWORD(v);
v = v * 7 / 0xFFFF;
*pvol = (int) v;
return 0;
}
rescode waveSetVolume(short newvol)
{
DWORD v;
MMRESULT res;
if (!waveinited) return 1;
// calculate a volume in the range 0..FFFF
v = (DWORD)newvol * 0xFFFF / 7;
v &= 0xFFFF;
// or in right channel volume
v |= (v<<16);
#if WINVER >= 0x0400
res = waveOutSetVolume(hwo, v);
#else
res = waveOutSetVolume(outdev, v);
#endif
// ignore error if function not supported
if (res==MMSYSERR_NOTSUPPORTED) return 0;
if (res) {
sounderror(res, 8);
return 1;
}
return 0;
}
#endif // iswin
#if ismac || isppc
rescode waveOpen(waveRate rate, waveBits bits, waveSpeak speak)
{
}
rescode waveClose()
{
}
rescode waveReset()
{
}
rescode waveGetPlayPtr(pmem *pptr)
{
}
rescode wavePlay()
{
}
rescode waveGetSampleCount(long *psize)
{
}
rescode waveGetVolume(short *pvol)
{
}
rescode waveSetVolume(short newvol)
{
}
#endif // ismac || isppc